package jtech;

import static jtech.Constantes.MOUSE_BUTTON_LEFT;
import static jtech.Constantes.MOUSE_BUTTON_MIDDLE;
import static jtech.Constantes.MOUSE_BUTTON_RIGHT;
import static jtech.Constantes.MOUSE_MOVE_DOWN;
import static jtech.Constantes.MOUSE_MOVE_LEFT;
import static jtech.Constantes.MOUSE_MOVE_RIGHT;
import static jtech.Constantes.MOUSE_MOVE_UP;
import static jtech.Constantes.MOUSE_WHEEL_DOWN;
import static jtech.Constantes.MOUSE_WHEEL_UP;

import java.awt.Point;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.util.ArrayList;
import java.util.List;

public class Input implements MouseListener, MouseWheelListener, MouseMotionListener,
		KeyListener {

	private static final int NUM_MOUSE_CODES = 10;
	private static final int NUM_KEY_CODES = 600;

    private int windowCenterX;
    private int windowCenterY;
	
	private GameAction[] keyActions = new GameAction[NUM_KEY_CODES];
	private GameAction[] mouseActions = new GameAction[NUM_MOUSE_CODES];

	private int getMouseButtonCode(MouseEvent e) {
		switch (e.getButton()) {
			case MouseEvent.BUTTON1:
				return MOUSE_BUTTON_LEFT;
			case MouseEvent.BUTTON2:
				return MOUSE_BUTTON_MIDDLE;
			case MouseEvent.BUTTON3:
				return MOUSE_BUTTON_RIGHT;
		}
		return -1;
	}
	
    public void setWindowCenter(Point windowCenter) {
        windowCenterX = windowCenter.x;
        windowCenterY = windowCenter.y;
    }

	private void mouseHelper(int codeNeg, int codePos, int amount) {
		GameAction gameAction;
		if (amount < 0) {
			gameAction = mouseActions[codeNeg];
		} else {
			gameAction = mouseActions[codePos];
		}
		if (gameAction != null) {
			gameAction.press(Math.abs(amount));
			gameAction.release();
		}
	}

	public GameAction getKeyAction(int keyCode) {
		if (keyCode < keyActions.length) {
			return keyActions[keyCode];
		}
		return null;
	}

	public GameAction getMouseAction(int mouseCode) {
		if (mouseCode < mouseActions.length) {
			return mouseActions[mouseCode];
		}
		return null;
	}

	public void mapToKey(GameAction gameAction, int keyCode) {
		keyActions[keyCode] = gameAction;
	}

	public void mapToMouse(GameAction gameAction, int mouseCode) {
		mouseActions[mouseCode] = gameAction;
	}

	public void clearMap(GameAction gameAction) {
		for (int i = 0; i < keyActions.length; i++) {
			if (keyActions[i] == gameAction) {
				keyActions[i] = null;
			}
		}
		for (int i = 0; i < mouseActions.length; i++) {
			if (mouseActions[i] == gameAction) {
				mouseActions[i] = null;
			}
		}
		gameAction.reset();
	}

	public List<String> getMaps(GameAction gameCode) {
		ArrayList<String> list = new ArrayList<String>();

		for (int i = 0; i < keyActions.length; i++) {
			if (keyActions[i] == gameCode) {
				list.add(getKeyName(i));
			}
		}

		for (int i = 0; i < mouseActions.length; i++) {
			if (mouseActions[i] == gameCode) {
				list.add(getMouseName(i));
			}
		}
		return list;
	}

	public void resetAllGameActions() {
		for (int i = 0; i < keyActions.length; i++) {
			if (keyActions[i] != null) {
				keyActions[i].reset();
			}
		}

		for (int i = 0; i < mouseActions.length; i++) {
			if (mouseActions[i] != null) {
				mouseActions[i].reset();
			}
		}
	}

	public String getKeyName(int keyCode) {
		return KeyEvent.getKeyText(keyCode);
	}

	public String getMouseName(int mouseCode) {
		switch (mouseCode) {
			case MOUSE_MOVE_LEFT:
				return "Mouse Left";
			case MOUSE_MOVE_RIGHT:
				return "Mouse Right";
			case MOUSE_MOVE_UP:
				return "Mouse Up";
			case MOUSE_MOVE_DOWN:
				return "Mouse Down";
			case MOUSE_WHEEL_UP:
				return "Mouse Wheel Up";
			case MOUSE_WHEEL_DOWN:
				return "Mouse Wheel Down";
			case MOUSE_BUTTON_LEFT:
				return "Mouse Button Left";
			case MOUSE_BUTTON_MIDDLE:
				return "Mouse Button Middle";
			case MOUSE_BUTTON_RIGHT:
				return "Mouse Button Right";
		}
		return "Unknown mouse code " + mouseCode;
	}
	
	// MouseMotionListener
    @Override
    public void mouseDragged(MouseEvent e) {
        mouseMoved(e);
    }

    @Override
    public void mouseMoved(MouseEvent e) {
        int x = e.getX(); //e.getXOnScreen();
        int y = e.getY(); //e.getYOnScreen();
        mouseHelper(MOUSE_MOVE_LEFT, MOUSE_MOVE_RIGHT, x-windowCenterX);
        mouseHelper(MOUSE_MOVE_UP, MOUSE_MOVE_DOWN, y-windowCenterY);
    }

    // MouseWheelListener
    @Override
    public void mouseWheelMoved(MouseWheelEvent e) {
        mouseHelper(MOUSE_WHEEL_UP, MOUSE_WHEEL_DOWN, e.getWheelRotation());
    }

    // MouseListener
    @Override
    public void mouseClicked(MouseEvent e) {
    
    }

    @Override
    public void mousePressed(MouseEvent e) {
        GameAction action = getMouseAction(getMouseButtonCode(e));
        if (action != null) {
            action.press();
        }
    }

    @Override
    public void mouseReleased(MouseEvent e) {
        GameAction action = getMouseAction(getMouseButtonCode(e));
        if (action != null) {
            action.release();
        }
    }

    @Override
    public void mouseEntered(MouseEvent e) {
        
    }

    @Override
    public void mouseExited(MouseEvent e) {
        
    }
    
    // KeyListener
    @Override
    public void keyTyped(KeyEvent e) {
        e.consume();
    }

    @Override
    public void keyPressed(KeyEvent e) {
        GameAction action = getKeyAction(e.getKeyCode());
        if (action != null) {
            action.press();
        }
    }

    @Override
    public void keyReleased(KeyEvent e) {
        GameAction action = getKeyAction(e.getKeyCode());
        if (action != null) {
            action.release();
        }
    }

}
